home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Pascal / Applications / NIH Image 1.59 / 1.59 Source / Projection.p < prev    next >
Encoding:
Text File  |  1995-07-24  |  43.0 KB  |  968 lines  |  [TEXT/PJMM]

  1. mentation
  2.  
  3.     const
  4.         bigpowerof2 = 8192;                               {used for integer trigonometric arithmetic}
  5.  
  6.     type
  7.         MHRIRealArray = array[1..MaxPics] of extended;
  8.         RealPoint = record
  9.                 x: extended;
  10.                 y: extended;
  11.             end;     {record}
  12.         IntPtr = ^integer;
  13.         LongPtr = ^LongInt;
  14.  
  15.     var
  16.         SliceInterval: extended;                                 {distance, in pixels, between original slices}
  17.         BoundRect: rect;                                      {boundary rectangle for a rectangular selection}
  18.         cancelled: boolean;
  19.                                                                                                                                                                                                                                         ProjSize: LongInt;
  20.  
  21.  
  22.  
  23. {******************************************************************************}
  24. {*     This procedure frees memory allocated for buffers used in projection calculations.                                       *}
  25. {******************************************************************************}
  26.     procedure DisposeProjectionPtrs (projptr, opaptr, brightcueptr: ptr; zbufptr, countbufptr, cuezbufptr: IntPtr; sumbufptr: LongPtr);
  27.     begin
  28.         if zbufptr <> nil then
  29.             DisposePtr(Ptr(zbufptr));
  30.         if opaptr <> nil then
  31.             DisposePtr(opaptr);
  32.         if sumbufptr <> nil then
  33.             DisposePtr(Ptr(sumbufptr));
  34.         if countbufptr <> nil then
  35.             DisposePtr(Ptr(countbufptr));
  36.         if cuezbufptr <> nil then
  37.             DisposePtr(Ptr(cuezbufptr));
  38.         if brightcueptr <> nil then
  39.             DisposePtr(brightcueptr);
  40.         if projptr <> nil then
  41.             DisposePtr(projptr);
  42.     end;
  43.  
  44.  
  45. {******************************************************************************}
  46. {*     This procedure projects each pixel of a volume (stack of slices) onto a plane as the volume rotates about    *}
  47. {*  the x-axis.  Integer arithmetic, precomputation of values, and iterative addition rather than multiplication  *}
  48. {*  inside a loop are used extensively to make the code run efficiently.  Projection parameters stored in global   *}
  49. {*  variables determine how the projection will be performed.  This procedure returns various buffers which   *}
  50. {*  are actually used by DoProject to find the final projected image for the volume of slices at the current angle.*}
  51. {******************************************************************************}
  52.     procedure DoOneProjectionX (nSlices, ycenter, zcenter: integer; projwidth, projheight: LongInt; costheta, sintheta: longint; projptr, opaptr, brightcueptr: ptr; zbufptr, cuezbufptr, countbufptr: IntPtr; sumbufptr: LongPtr; str: string);
  53.         var
  54.             i, j, k,                                                 {loop indices}
  55.             thispixel: integer;                              {the current pixel to be projected}
  56.             offset, offsetinit: longint;                   {precomputed offsets into an image buffer}
  57.             projaddr,                                            {buffer address for final projected image}
  58.             opaaddr,                                              {buffer address for opacity surface projection component}
  59.             brightcueaddr,                                   {buffer address for brightest-point projection with interior depth cues}
  60.             zbufaddr,                                            {z-buffer address for surface projections (nearest-point/opacity)}
  61.             cuezbufaddr,                                       {z-buffer address for brightest-point projection with interior depth cues}
  62.             countbufaddr,                                     {buffer addr for counting pixels in mean-value projection}
  63.             sumbufaddr: longint;                         {buffer addr for summing pixels in mean-value projection}
  64.             z,                                                        {z-coordinate of points in current slice before rotation}
  65.             ynew, znew,                                       {y- and z-coordinates of current point after rotation}
  66.             zmax, zmin,                                       {z-coordinates of first and last slices before rotation}
  67.             zmaxminuszmintimes100: longint;  {precomputed values to save time in loops}
  68.             c100minusDepthCueInt, c100minusDepthCueSurf: integer;
  69.             DepthCueIntlessthan100, DepthCueSurflessthan100: boolean;
  70.             OpacityOrNearestPt, OpacityAndNotNearestPt: boolean;
  71.             MeanVal, BrightestPt: boolean;
  72.             ysintheta, ycostheta,                          {values used in rotational calculations before projection}
  73.             zsintheta, zcostheta, ysinthetainit, ycosthetainit: longint;
  74.             p,                                                        {pointer to final projected image buffer}
  75.             op,                                                      {pointer to opacity surface projection buffer}
  76.             bp: ptr;                                              {pointer to brightest-point projection buffer with interior depth cues}
  77.             zp,                                                      {pointer to surface projection (nearest-point/opacity) z-buffer}
  78.             qp,                                                      {pointer to z-buffer for brightest-point projection with interior depth cues}
  79.             cp: IntPtr;                                          {pointer to buffer for counting pixels for mean-value projection}
  80.             sp: LongPtr;                                       {pointer to mean-value summing buffer}
  81.             width: integer;
  82.             theLine: LineType;
  83.     begin
  84.         with BoundRect do begin                    {precompute values to avoid computations in loop}
  85.                 width := right - left;
  86.                 zmax := zcenter + projheight div 2; {find z-coordinates of first and last slices}
  87.                 zmin := zcenter - projheight div 2;
  88.                 zmaxminuszmintimes100 := 100 * (zmax - zmin);
  89.                 c100minusDepthCueInt := 100 - DepthCueInt;
  90.                 c100minusDepthCueSurf := 100 - DepthCueSurf;
  91.                 DepthCueIntlessthan100 := DepthCueInt < 100;
  92.                 DepthCueSurflessthan100 := DepthCueSurf < 100;
  93.                 OpacityOrNearestPt := (ProjectionMethod = NearestPoint) or (Opacity > 0);
  94.                 OpacityAndNotNearestPt := (Opacity > 0) and (ProjectionMethod <> NearestPoint);
  95.                 MeanVal := ProjectionMethod = MeanValue;
  96.                 BrightestPt := ProjectionMethod = BrightestPoint;
  97.                 projaddr := ord4(projptr);
  98.                 opaaddr := ord4(opaptr);
  99.                 brightcueaddr := ord4(brightcueptr);
  100.                 zbufaddr := ord4(zbufptr);
  101.                 cuezbufaddr := ord4(cuezbufptr);
  102.                 countbufaddr := ord4(countbufptr);
  103.                 sumbufaddr := ord4(sumbufptr);
  104.                 ycosthetainit := (top - ycenter - 1) * costheta;
  105.                 ysinthetainit := (top - ycenter - 1) * sintheta;
  106.                 offsetinit := ((projheight - bottom + top) div 2) * projwidth + (projwidth - right + left) div 2 - 1;
  107.                 for k := 1 to nSlices do begin
  108.                         SelectSlice(k);
  109.                         z := round((k - 1) * SliceInterval) - zcenter;
  110.                         zcostheta := z * costheta;
  111.                         zsintheta := z * sintheta;
  112.                         ycostheta := ycosthetainit;
  113.                         ysintheta := ysinthetainit;
  114.                         for j := top to bottom - 1 do begin               {read each row in the current slice}
  115.                                 ycostheta := ycostheta + costheta;               {rotate about x-axis and find new y,z}
  116.                                 ysintheta := ysintheta + sintheta;               {x-coordinates will not change}
  117.                                 ynew := (ycostheta - zsintheta) div bigpowerof2 + ycenter - top;
  118.                                 znew := (ysintheta + zcostheta) div bigpowerof2 + zcenter;
  119.                                 offset := offsetinit + ynew * projwidth;
  120.                                 GetLine(left, j, width, theLine);
  121.                                 for i := 0 to width - 1 do begin             {read each pixel in current row and project it}
  122.                                         thispixel := theLine[i];
  123.                                         offset := offset + 1;
  124.                                         if (offset >= ProjSize) or (offset < 0) then
  125.                                             offset := 0;
  126.                                         if (thispixel <= TransparencyUpper) and (thispixel >= TransparencyLower) then begin
  127.                                                 if OpacityOrNearestPt then begin
  128.                                                         zp := IntPtr(zbufaddr + offset + offset);
  129.                                                         if (znew < zp^) then begin
  130.                                                                 zp^ := znew;
  131.                                                                 if OpacityAndNotNearestPt then begin
  132.                                                                         op := ptr(opaaddr + offset);
  133.                                                                         if (DepthCueSurflessthan100) then
  134.                                                                             op^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  135.                                                                         else
  136.                                                                             op^ := thispixel;
  137.                                                                     end
  138.                                                                 else begin
  139.                                                                         p := ptr(projaddr + offset);
  140.                                                                         if DepthCueSurflessthan100 then
  141.                                                                             p^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  142.                                                                         else
  143.                                                                             p^ := thispixel;
  144.                                                                     end;
  145.                                                             end;
  146.                                                     end;     {NearestPoint case}
  147.                                                 if MeanVal then begin
  148.                                                         sp := LongPtr(sumbufaddr + offset + offset + offset + offset);
  149.                                                         sp^ := sp^ + thispixel;
  150.                                                         cp := IntPtr(countbufaddr + offset + offset);
  151.                                                         cp^ := cp^ + 1;
  152.                                                     end     {MeanValue case}
  153.                                                 else if BrightestPt then begin
  154.                                                         if (DepthCueIntlessthan100) then begin
  155.                                                                 p := ptr(projaddr + offset);
  156.                                                                 bp := ptr(brightcueaddr + offset);
  157.                                                                 qp := IntPtr(cuezbufaddr + offset + offset);
  158.                                                                 if (thispixel < BAND(bp^, 255)) or ((thispixel = BAND(bp^, 255)) and (znew < qp^)) then begin
  159.                                                                         bp^ := thispixel;                     {use z-buffer to ensure that if depth-cueing is on,  }
  160.                                                                         qp^ := znew;                            {the closer of two equally-bright points is displayed}
  161.                                                                         p^ := 255 - (DepthCueInt * (255 - thispixel) div 100 + (c100minusDepthCueInt) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100);
  162.                                                                     end;     {then}
  163.                                                             end
  164.                                                         else begin
  165.                                                                 p := ptr(projaddr + offset);
  166.                                                                 if (thispixel < BAND(p^, 255)) then
  167.                                                                     p^ := thispixel;
  168.                                                             end;     {else}
  169.                                                     end;     {BrightestPoint case}
  170.                                             end;
  171.                                     end;     {for j}
  172.                             end;     {for i}
  173.                         UpdateMeter(10 + (k * 90) div nSlices, str);
  174.                         if CommandPeriod then begin
  175.                                 cancelled := true;
  176.                                 beep;
  177.                                 leave;
  178.                             end;
  179.                     end;     {for k}
  180.             end;     {with}
  181.     end;     {procedure DoOneProjectionX}
  182.  
  183.  
  184.  
  185. {******************************************************************************}
  186. {*     This procedure projects each pixel of a volume (stack of slices) onto a plane as the volume rotates about    *}
  187. {*  the y-axis.  Integer arithmetic, precomputation of values, and iterative addition rather than multiplication  *}
  188. {*  inside a loop are used extensively to make the code run efficiently.  Projection parameters stored in global   *}
  189. {*  variables determine how the projection will be performed.  This procedure returns various buffers which   *}
  190. {*  are actually used by DoProject to find the final projected image for the volume of slices at the current angle.*}
  191. {******************************************************************************}
  192.     procedure DoOneProjectionY (nSlices, xcenter, zcenter: integer; projwidth, projheight: LongInt; costheta, sintheta: longint; projptr, opaptr, brightcueptr: ptr; zbufptr, cuezbufptr, countbufptr: IntPtr; sumbufptr: LongPtr; str: string);
  193.         var
  194.             i, j, k, thispixel: integer;
  195.             offset, offsetinit: longint;
  196.             projaddr, opaaddr, brightcueaddr, zbufaddr, cuezbufaddr, countbufaddr, sumbufaddr: longint;
  197.             z, xnew, znew, zmax, zmin, zmaxminuszmintimes100: longint;
  198.             c100minusDepthCueInt, c100minusDepthCueSurf: integer;
  199.             DepthCueIntlessthan100, DepthCueSurflessthan100: boolean;
  200.             OpacityOrNearestPt, OpacityAndNotNearestPt: boolean;
  201.             MeanVal, BrightestPt: boolean;
  202.             xsintheta, xcostheta, zsintheta, zcostheta, xsinthetainit, xcosthetainit: longint;
  203.             p, op, bp: ptr;
  204.             zp, qp, cp: IntPtr;
  205.             sp: LongPtr;
  206.             width: integer;
  207.             aLine: LineType;
  208.     begin
  209.         with BoundRect do begin
  210.                 width := right - left;
  211.                 zmax := zcenter + projwidth div 2;
  212.                 zmin := zcenter - projwidth div 2;
  213.                 zmaxminuszmintimes100 := 100 * (zmax - zmin);
  214.                 c100minusDepthCueInt := 100 - DepthCueInt;
  215.                 c100minusDepthCueSurf := 100 - DepthCueSurf;
  216.                 DepthCueIntlessthan100 := DepthCueInt < 100;
  217.                 DepthCueSurflessthan100 := DepthCueSurf < 100;
  218.                 OpacityOrNearestPt := (ProjectionMethod = NearestPoint) or (Opacity > 0);
  219.                 OpacityAndNotNearestPt := (Opacity > 0) and (ProjectionMethod <> NearestPoint);
  220.                 MeanVal := ProjectionMethod = MeanValue;
  221.                 BrightestPt := ProjectionMethod = BrightestPoint;
  222.                 projaddr := ord4(projptr);
  223.                 opaaddr := ord4(opaptr);
  224.                 brightcueaddr := ord4(brightcueptr);
  225.                 zbufaddr := ord4(zbufptr);
  226.                 cuezbufaddr := ord4(cuezbufptr);
  227.                 countbufaddr := ord4(countbufptr);
  228.                 sumbufaddr := ord4(sumbufptr);
  229.                 xcosthetainit := (left - xcenter - 1) * costheta;
  230.                 xsinthetainit := (left - xcenter - 1) * sintheta;
  231.                 for k := 1 to nSlices do begin
  232.                         SelectSlice(k);
  233.                         z := round((k - 1) * SliceInterval) - zcenter;
  234.                         zcostheta := z * costheta;
  235.                         zsintheta := z * sintheta;
  236.                         offsetinit := ((projheight - bottom + top) div 2) * projwidth + (projwidth - right + left) div 2 - projwidth;
  237.                         for j := top to bottom - 1 do begin
  238.                                 xcostheta := xcosthetainit;
  239.                                 xsintheta := xsinthetainit;
  240.                                 offsetinit := offsetinit + projwidth;
  241.                                 GetLine(left, j, width, aLine);
  242.                                 for i := 0 to width - 1 do begin
  243.                                         thispixel := aLine[i];
  244.                                         xcostheta := xcostheta + costheta;
  245.                                         xsintheta := xsintheta + sintheta;
  246.                                         if (thispixel <= TransparencyUpper) and (thispixel >= TransparencyLower) then begin
  247.                                                 xnew := (xcostheta + zsintheta) div bigpowerof2 + xcenter - left;
  248.                                                 znew := (zcostheta - xsintheta) div bigpowerof2 + zcenter;
  249.                                                 offset := offsetinit + xnew;
  250.                                                 if (offset >= ProjSize) or (offset < 0) then
  251.                                                     offset := 0;
  252.                                                 if OpacityOrNearestPt then begin
  253.                                                         zp := IntPtr(zbufaddr + offset + offset);
  254.                                                         if (znew < zp^) then begin
  255.                                                                 zp^ := znew;
  256.                                                                 if OpacityAndNotNearestPt then begin
  257.                                                                         op := ptr(opaaddr + offset);
  258.                                                                         if (DepthCueSurflessthan100) then
  259.                                                                             op^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  260.                                                                         else
  261.                                                                             op^ := thispixel;
  262.                                                                     end
  263.                                                                 else begin
  264.                                                                         p := ptr(projaddr + offset);
  265.                                                                         if DepthCueSurflessthan100 then
  266.                                                                             p^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  267.                                                                         else
  268.                                                                             p^ := thispixel;
  269.                                                                     end;
  270.                                                             end;
  271.                                                     end;     {NearestPoint case}
  272.                                                 if MeanVal then begin
  273.                                                         sp := LongPtr(sumbufaddr + offset + offset + offset + offset);
  274.                                                         sp^ := sp^ + thispixel;
  275.                                                         cp := IntPtr(countbufaddr + offset + offset);
  276.                                                         cp^ := cp^ + 1;
  277.                                                     end     {MeanValue case}
  278.                                                 else if BrightestPt then begin
  279.                                                         if (DepthCueIntlessthan100) then begin
  280.                                                                 p := ptr(projaddr + offset);
  281.                                                                 bp := ptr(brightcueaddr + offset);
  282.                                                                 qp := IntPtr(cuezbufaddr + offset + offset);
  283.                                                                 if (thispixel < BAND(bp^, 255)) or ((thispixel = BAND(bp^, 255)) and (znew < qp^)) then begin
  284.                                                                         bp^ := thispixel;
  285.                                                                         qp^ := znew;
  286.                                                                         p^ := 255 - (DepthCueInt * (255 - thispixel) div 100 + (c100minusDepthCueInt) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100);
  287.                                                                     end;     {then}
  288.                                                             end
  289.                                                         else begin
  290.                                                                 p := ptr(projaddr + offset);
  291.                                                                 if (thispixel < BAND(p^, 255)) then
  292.                                                                     p^ := thispixel;
  293.                                                             end;     {else}
  294.                                                     end;     {BrightestPoint case}
  295.                                             end;
  296.                                     end;     {for j}
  297.                             end;     {for i}
  298.                         UpdateMeter(10 + (k * 90) div nSlices, str);
  299.                         if CommandPeriod then begin
  300.                                 cancelled := true;
  301.                                 beep;
  302.                                 leave;
  303.                             end;
  304.                     end;     {for k}
  305.             end;     {with}
  306.     end;     {procedure DoOneProjectionY}
  307.  
  308.  
  309.  
  310. {******************************************************************************}
  311. {*     This procedure projects each pixel of a volume (stack of slices) onto a plane as the volume rotates about    *}
  312. {*  the z-axis.  Integer arithmetic, precomputation of values, and iterative addition rather than multiplication  *}
  313. {*  inside a loop are used extensively to make the code run efficiently.  Projection parameters stored in global   *}
  314. {*  variables determine how the projection will be performed.  This procedure returns various buffers which   *}
  315. {*  are actually used by DoProject to find the final projected image for the volume of slices at the current angle.*}
  316. {******************************************************************************}
  317.     procedure DoOneProjectionZ (nSlices, xcenter, ycenter, zcenter: integer; projwidth, projheight: LongInt; costheta, sintheta: longint; projptr, opaptr, brightcueptr: ptr; zbufptr, cuezbufptr, countbufptr: IntPtr; sumbufptr: LongPtr; str: string);
  318.         var
  319.             i, j, k, thispixel: integer;
  320.             offset, offsetinit: longint;
  321.             projaddr, opaaddr, brightcueaddr, zbufaddr, cuezbufaddr, countbufaddr, sumbufaddr: longint;
  322.             z, xnew, ynew, zmax, zmin, zmaxminuszmintimes100: longint;
  323.             c100minusDepthCueInt, c100minusDepthCueSurf: integer;
  324.             DepthCueIntlessthan100, DepthCueSurflessthan100: boolean;
  325.             OpacityOrNearestPt, OpacityAndNotNearestPt: boolean;
  326.             MeanVal, BrightestPt: boolean;
  327.             xsintheta, xcostheta, ysintheta, ycostheta: longint;
  328.             xsinthetainit, xcosthetainit, ysinthetainit, ycosthetainit: longint;
  329.             p, op, bp: ptr;
  330.             zp, qp, cp: IntPtr;
  331.             sp: LongPtr;
  332.             width: integer;
  333.             theLine: LineType;
  334.     begin
  335.         with BoundRect do begin
  336.                 width := right - left;
  337.                 zmax := zcenter + projwidth div 2;
  338.                 zmin := zcenter - projwidth div 2;
  339.                 zmaxminuszmintimes100 := 100 * (zmax - zmin);
  340.                 c100minusDepthCueInt := 100 - DepthCueInt;
  341.                 c100minusDepthCueSurf := 100 - DepthCueSurf;
  342.                 DepthCueIntlessthan100 := DepthCueInt < 100;
  343.                 DepthCueSurflessthan100 := DepthCueSurf < 100;
  344.                 OpacityOrNearestPt := (ProjectionMethod = NearestPoint) or (Opacity > 0);
  345.                 OpacityAndNotNearestPt := (Opacity > 0) and (ProjectionMethod <> NearestPoint);
  346.                 MeanVal := ProjectionMethod = MeanValue;
  347.                 BrightestPt := ProjectionMethod = BrightestPoint;
  348.                 projaddr := ord4(projptr);
  349.                 opaaddr := ord4(opaptr);
  350.                 brightcueaddr := ord4(brightcueptr);
  351.                 zbufaddr := ord4(zbufptr);
  352.                 cuezbufaddr := ord4(cuezbufptr);
  353.                 countbufaddr := ord4(countbufptr);
  354.                 sumbufaddr := ord4(sumbufptr);
  355.                 xcosthetainit := (left - xcenter - 1) * costheta;
  356.                 xsinthetainit := (left - xcenter - 1) * sintheta;
  357.                 ycosthetainit := (top - ycenter - 1) * costheta;
  358.                 ysinthetainit := (top - ycenter - 1) * sintheta;
  359.                 offsetinit := ((projheight - bottom + top) div 2) * projwidth + (projwidth - right + left) div 2 + left - 1;
  360.                 for k := 1 to nSlices do begin
  361.                         SelectSlice(k);
  362.                         z := round((k - 1) * SliceInterval) - zcenter;
  363.                         ycostheta := ycosthetainit;
  364.                         ysintheta := ysinthetainit;
  365.                         for j := top to bottom - 1 do begin
  366.                                 ycostheta := ycostheta + costheta;
  367.                                 ysintheta := ysintheta + sintheta;
  368.                                 xcostheta := xcosthetainit;
  369.                                 xsintheta := xsinthetainit;
  370.                                 GetLine(left, j, width, theLine);
  371.                                 for i := 0 to width - 1 do begin
  372.                                         thisPixel := theLine[i];
  373.                                         xcostheta := xcostheta + costheta;
  374.                                         xsintheta := xsintheta + sintheta;
  375.                                         if (thispixel <= TransparencyUpper) and (thispixel >= TransparencyLower) then begin
  376.                                                 xnew := (xcostheta - ysintheta) div bigpowerof2 + xcenter - left;
  377.                                                 ynew := (xsintheta + ycostheta) div bigpowerof2 + ycenter - top;
  378.                                                 offset := offsetinit + ynew * projwidth + xnew;
  379.                                                 if (offset >= ProjSize) or (offset < 0) then
  380.                                                     offset := 0;
  381.                                                 if OpacityOrNearestPt then begin
  382.                                                         zp := IntPtr(zbufaddr + offset + offset);
  383.                                                         if (z < zp^) then begin
  384.                                                                 zp^ := z;
  385.                                                                 if OpacityAndNotNearestPt then begin
  386.                                                                         op := ptr(opaaddr + offset);
  387.                                                                         if (DepthCueSurflessthan100) then
  388.                                                                             op^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - z) div zmaxminuszmintimes100)
  389.                                                                         else
  390.                                                                             op^ := thispixel;
  391.                                                                     end
  392.                                                                 else begin
  393.                                                                         p := ptr(projaddr + offset);
  394.                                                                         if DepthCueSurflessthan100 then
  395.                                                                             p^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - z) div zmaxminuszmintimes100)
  396.                                                                         else
  397.                                                                             p^ := thispixel;
  398.                                                                     end;
  399.                                                             end;
  400.                                                     end;     {NearestPoint case}
  401.                                                 if MeanVal then begin
  402.                                                         sp := LongPtr(sumbufaddr + offset + offset + offset + offset);
  403.                                                         sp^ := sp^ + thispixel;
  404.                                                         cp := IntPtr(countbufaddr + offset + offset);
  405.                                                         cp^ := cp^ + 1;
  406.                                                     end     {MeanValue case}
  407.                                                 else if BrightestPt then begin
  408.                                                         if (DepthCueIntlessthan100) then begin
  409.                                                                 p := ptr(projaddr + offset);
  410.                                                                 bp := ptr(brightcueaddr + offset);
  411.                                                                 qp := IntPtr(cuezbufaddr + offset + offset);
  412.                                                                 if (thispixel < BAND(bp^, 255)) or ((thispixel = BAND(bp^, 255)) and (z < qp^)) then begin
  413.                                                                         bp^ := thispixel;
  414.                                                                         qp^ := z;
  415.                                                                         p^ := 255 - (DepthCueInt * (255 - thispixel) div 100 + (c100minusDepthCueInt) * (255 - thispixel) * (zmax - z) div zmaxminuszmintimes100);
  416.                                                                     end;     {then}
  417.                                                             end
  418.                                                         else begin
  419.                                                                 p := ptr(projaddr + offset);
  420.                                                                 if (thispixel < BAND(p^, 255)) then
  421.                                                                     p^ := thispixel;
  422.                                                             end;     {else}
  423.                                                     end;     {BrightestPoint case}
  424.                                             end;
  425.                                     end;     {for j}
  426.                             end;     {for i}
  427.                         UpdateMeter(10 + (k * 90) div nSlices, str);
  428.                         if CommandPeriod then begin
  429.                                 cancelled := true;
  430.                                 beep;
  431.                                 leave;
  432.                             end;
  433.                     end;     {for k}
  434.             end;     {with}
  435.     end;     {procedure DoOneProjectionZ}
  436.  
  437.  
  438.  
  439. {******************************************************************************}
  440. {*     This code initializes buffers by filling them with uniform values. The *}
  441. {*     The buffer can be filled with one, two or four byte values.            *}
  442. {******************************************************************************}
  443.     procedure InitializeBuffer (p: ptr; size: longint; value, step: integer);
  444.     type
  445.         IntPtrType=^integer;
  446.         LongPtrType=^LongInt;
  447.     var
  448.         i, Lstep: longint;
  449.         IntPtr:IntPtrTYpe;
  450.         LongPtr:LongPtrType;
  451.     begin
  452.         Lstep:=step;
  453.         case step of
  454.             1: for i := 1 to size do begin
  455.                     p^ := value;
  456.                     p := Ptr(ord4(p) + Lstep);
  457.                 end;
  458.             2: begin
  459.                     IntPtr:=IntPtrType(p);
  460.                     for i := 1 to size do begin
  461.                         IntPtr^ := value;
  462.                         IntPtr := IntPtrType(ord4(IntPtr) + Lstep);
  463.                     end;
  464.                 end;
  465.             4: begin
  466.                     LongPtr:=LongPtrType(p);
  467.                     for i := 1 to size do begin
  468.                         LongPtr^ := value;
  469.                         LongPtr := LongPtrType(ord4(LongPtr) + Lstep);
  470.                     end;
  471.                 end;
  472.         end;
  473.     end;
  474.  
  475.  
  476.  
  477. {******************************************************************************}
  478. {*     This procedure creates a sequence of projections of a rotating volume (stack of slices) onto a plane using   *}
  479. {*  nearest-point (surface), brightest-point, or mean-value projection or a weighted combination of nearest- *}
  480. {*  point projection with either of the other two methods (partial opacity).  The user may choose to rotate the   *}
  481. {*  volume about any of the three orthogonal axes (x,y, or z), make portions of the volume transparent, or add  *}
  482. {*  a greater degree of visual realism by employing depth cues.                                                                               *}
  483. {******************************************************************************}
  484. procedure DoProjection;
  485.     var
  486.         tport: Grafptr;
  487.         nSlices: integer;                                      {number of slices in volume}
  488.         projwidth, projheight: LongInt;              {dimensions of projection image}
  489.         xcenter, ycenter, zcenter: integer;         {coordinates of center of volume of rotation}
  490.         theta: integer;                                          {current angle of rotation in degrees}
  491.         thetarad: extended;                                          {current angle of rotation in radians}
  492.         sintheta, costheta: longint;                      {sine and cosine of current angle}
  493.         xsinthetainit, xcosthetainit: longint;      {precomputed products to avoid mult in loops}
  494.         offset, MemoryRequired: longint;
  495.         p, op, bp, projptr, opaptr, brightcueptr: ptr;
  496.         zp, zbufptr, qp, cuezbufptr, countbufptr, cp: IntPtr;
  497.         sp, sumbufptr: LongPtr;
  498.         curval, prevval, nextval, aboveval, belowval: integer;
  499.         ignore: integer;                                        {irrelevant return value from a function}
  500.         ticksinit, tickstogo, TicksForOneProjection: longint;
  501.         str, TimeStr, seconds: str255;
  502.         SaveProjectionsTemp, AutoSelectAll, AllocatingBuffers: boolean;
  503.         n, nProjections, angle: integer;
  504.         SourceInfo, DestInfo: InfoPtr;
  505.         width, height: LongInt;
  506.  
  507.     procedure Abort;
  508.     begin
  509.         DisposeProjectionPtrs(projptr, opaptr, brightcueptr, zbufptr, countbufptr, cuezbufptr, sumbufptr);
  510.         if AllocatingBuffers and (MaxBlock > 20000) then
  511.             PutError('Insufficient Memory.');
  512.         AbortMacro;
  513.         {exit(DoProjection);} {ppc-bug}
  514.     end;
  515.  
  516. begin
  517.     ShowWatch;
  518.     AutoSelectAll := not Info^.RoiShowing;
  519.     if AutoSelectAll then
  520.         SelectAll(false);
  521.     if NotInBounds then
  522.         exit(DoProjection);
  523.     cancelled := false;
  524.     SourceInfo := Info;
  525.     GetPort(tPort);
  526.     with Info^ do begin
  527.             SetPort(GrafPtr(osPort));
  528.             BoundRect := Roirect;
  529.         end;
  530.     if (AngleInc = 0) and (TotalAngle <> 0) then
  531.         AngleInc := 5;
  532.     angle := 0;
  533.     nProjections := 0;
  534.     if AngleInc = 0 then
  535.         nProjections := 1
  536.     else
  537.         while angle <= TotalAngle do begin
  538.                 nProjections := nProjections + 1;
  539.                 angle := angle + AngleInc;
  540.             end;
  541.     if angle > 360 then
  542.         nProjections := nProjections - 1;
  543.     if nProjections <= 0 then
  544.         nProjections := 1;
  545.     nSlices := Info^.StackInfo^.nSlices;         {get number of slices in volume}
  546.     SliceInterval := info^.StackInfo^.SliceSpacing;
  547.     with BoundRect do begin
  548.             width := right - left;
  549.             height := bottom - top;
  550.             xcenter := (left + right) div 2;          {find center of volume of rotation}
  551.             ycenter := (top + bottom) div 2;
  552.             zcenter := round(nSlices * SliceInterval / 2.0);
  553.             if MinProjSize and (AxisOfRotation <> ZAxis) then begin
  554.                     case AxisOfRotation of                    {find dimensions of projection image}
  555.                         XAxis:  begin
  556.                                 projheight := round(sqrt(sqr(nSlices * SliceInterval) + height * height));
  557.                                 projwidth := right - left;
  558.                             end;     {XAxis}
  559.                         YAxis:  begin
  560.                                 projwidth := round(sqrt(sqr(nSlices * SliceInterval) + ord4(right - left) * (right - left)));
  561.                                 projheight := bottom - top;
  562.                             end;     {YAxis}
  563.                     end;     {case}
  564.                 end     {then}
  565.             else begin
  566.                     projwidth := round(sqrt(sqr(nSlices * SliceInterval) + width * width));
  567.                     projheight := round(sqrt(sqr(nSlices * SliceInterval) + height * height));
  568.                 end;     {else make all windows the same size regardless of rotation axis}
  569.         end;     {with BoundRect}
  570.     if odd(projwidth) then
  571.         projwidth := projwidth + 1;
  572.     projptr := nil;
  573.     zbufptr := nil;
  574.     opaptr := nil;
  575.     brightcueptr := nil;
  576.     cuezbufptr := nil;
  577.     sumbufptr := nil;
  578.     countbufptr := nil;
  579.     AllocatingBuffers := true;
  580.     projsize := projwidth * projheight;
  581.     projptr := NewPtr(projsize);
  582.     if projptr = nil then
  583.         begin Abort; exit(DoProjection) end;
  584.  
  585.     if (ProjectionMethod = NearestPoint) or (Opacity > 0) then begin    {get other required buffers}
  586.             zbufptr := IntPtr(NewPtr(projsize * 2));
  587.             if zbufptr = nil then
  588.                 begin Abort; exit(DoProjection) end;
  589.         end;
  590.     if (Opacity > 0) and (ProjectionMethod <> NearestPoint) then begin
  591.             opaptr := NewPtr(projsize);
  592.             if opaptr = nil then
  593.                 begin Abort; exit(DoProjection) end;
  594.         end;
  595.     if (ProjectionMethod = BrightestPoint) and (DepthCueInt < 100) then begin
  596.             brightcueptr := NewPtr(projsize);
  597.             cuezbufptr := IntPtr(NewPtr(projsize * 2));
  598.             if (brightcueptr = nil) or (cuezbufptr = nil) then
  599.                 begin Abort; exit(DoProjection) end;
  600.         end;
  601.     if (ProjectionMethod = MeanValue) then begin
  602.             sumbufptr := LongPtr(NewPtr(projsize * 4));
  603.             countbufptr := IntPtr(NewPtr(projsize * 2));
  604.             if (sumbufptr = nil) or (countbufptr = nil) then
  605.                 begin Abort; exit(DoProjection) end;
  606.         end;
  607.     AllocatingBuffers := false;
  608.     SaveProjectionsTemp := FALSE;              {check whether we have enough memory to open}
  609.     MemoryRequired := nProjections * projsize + SizeOf(PicInfo) + MinFree;
  610.     if (MemoryRequired > FreeMem) and not (SaveProjections) then begin
  611.             str := 'Insufficient memory to create entire stack of projections.  Projection images will be saved to disk.';
  612.             if (PutMessageWithCancel(str) = cancel) then
  613.                 begin Abort; exit(DoProjection) end;
  614.             SaveProjections := TRUE;
  615.             SaveProjectionsTemp := TRUE;
  616.         end;
  617.     if (SaveProjections) then begin           {prepare to save projections as created if desired}
  618.             SaveAsWhat := AsTiff;
  619.             SaveAllState := SaveAllStage1;
  620.         end;
  621.     TimeStr := '?';
  622.     theta := InitAngle;                                     {begin rotation with user-specified angle}
  623.     ticksinit := TickCount;
  624.     for n := 1 to nProjections do begin
  625.             if (SaveProjections) or (n = 1) then begin    {open new window or stack slice}
  626.                     if SaveProjections then
  627.                         case AxisOfRotation of
  628.                             XAxis: 
  629.                                 str := StringOf('Projection X ', theta:3);
  630.                             YAxis: 
  631.                                 str := StringOf('Projection Y ', theta:3);
  632.                             ZAxis: 
  633.                                 str := StringOf('Projection Z ', theta:3);
  634.                         end
  635.                     else
  636.                         str := 'Projections';
  637.                     if not NewPicWindow(str, projwidth, projheight) then
  638.                         begin Abort; exit(DoProjection) end;
  639.                 end
  640.             else if not (AddSlice(false)) then
  641.                 begin Abort; exit(DoProjection) end;
  642.             str := concat('Projecting: ', long2str(n), '/', long2str(nProjections), ' (', long2str(Theta), '°', ', ', TimeStr, ')');
  643.             ShowMeter;
  644.             UpdateMeter(0, str);
  645.             thetarad := theta * pi / 180.0;
  646.             costheta := round(bigpowerof2 * cos(thetarad));
  647.             sintheta := round(bigpowerof2 * sin(thetarad));
  648.             p := projptr;                                          {initialize required projection buffers}
  649.             InitializeBuffer(p, projsize, 255, 1);
  650.             if (ProjectionMethod = NearestPoint) or (Opacity > 0) then begin
  651.                     zp := zbufptr;
  652.                     InitializeBuffer(Ptr(zp), projsize, 32767, 2);
  653.                 end;     {then}
  654.             if (Opacity > 0) and (ProjectionMethod <> NearestPoint) then begin
  655.                     op := opaptr;
  656.                     InitializeBuffer(op, projsize, 255, 1);
  657.                 end;     {then}
  658.             if (ProjectionMethod = MeanValue) then begin
  659.                     sp := sumbufptr;
  660.                     cp := countbufptr;
  661.                     InitializeBuffer(Ptr(sp), projsize, 0, 4);
  662.                     InitializeBuffer(Ptr(cp), projsize, 0, 2);
  663.                 end;
  664.             if (ProjectionMethod = BrightestPoint) and (DepthCueInt < 100) then begin
  665.                     bp := brightcueptr;
  666.                     InitializeBuffer(bp, projsize, 255, 1);
  667.                     qp := cuezbufptr;
  668.                     InitializeBuffer(Ptr(qp), projsize, 255, 2);
  669.                 end;     {then}
  670.             UpdateMeter(10, str);
  671.             DestInfo := Info;
  672.             Info := SourceInfo;
  673.             case AxisOfRotation of
  674.                 XAxis: 
  675.                     DoOneProjectionX(nSlices, ycenter, zcenter, projwidth, projheight, costheta, sintheta, projptr, opaptr, brightcueptr, zbufptr, cuezbufptr, countbufptr, sumbufptr, str);
  676.                 YAxis: 
  677.                     DoOneProjectionY(nSlices, xcenter, zcenter, projwidth, projheight, costheta, sintheta, projptr, opaptr, brightcueptr, zbufptr, cuezbufptr, countbufptr, sumbufptr, str);
  678.                 ZAxis: 
  679.                     DoOneProjectionZ(nSlices, xcenter, ycenter, zcenter, projwidth, projheight, costheta, sintheta, projptr, opaptr, brightcueptr, zbufptr, cuezbufptr, countbufptr, sumbufptr, str);
  680.             end;
  681.             Info := DestInfo;
  682.             if n = 1 then
  683.                 TicksForOneProjection := TickCount - TicksInit;
  684.             TicksToGo := (nProjections - n) * TicksForOneProjection;
  685.             NumToString((TicksToGo div 60) mod 60, seconds);
  686.             if length(seconds) = 1 then
  687.                 seconds := concat('0', seconds);
  688.             timestr := concat(long2str(TicksToGo div 3600), ':', seconds);
  689.             if (ProjectionMethod = MeanValue) then begin
  690.                     p := projptr;                                    {calculate the mean-value image from returned info}
  691.                     sp := sumbufptr;
  692.                     cp := countbufptr;
  693.                     for offset := 0 to projsize - 1 do begin
  694.                             if (cp^ > 0) then
  695.                                 p^ := sp^ div cp^;
  696.                             p := ptr(ord4(p) + 1);
  697.                             sp := LongPtr(ord4(sp) + 4);
  698.                             cp := IntPtr(ord4(cp) + 2);
  699.                         end;     {for}
  700.                 end;     {then}
  701.             if (Opacity > 0) and (ProjectionMethod <> NearestPoint) then begin
  702.                     p := projptr;                                    {calculate surface proj component (opacity on)}
  703.                     op := opaptr;                                     {and combine with another proj component}
  704.                     for offset := 0 to projsize - 1 do begin
  705.                             p^ := (Opacity * BAND(op^, 255) + (100 - Opacity) * BAND(p^, 255)) div 100;
  706.                             p := ptr(ord4(p) + 1);
  707.                             op := ptr(ord4(op) + 1);
  708.                         end;     {for}
  709.                 end;     {then}
  710.             if (AxisOfRotation = ZAxis) then begin  {interpolate for z-axis rotation}
  711.                     p := ptr(ord4(projptr) + projwidth);
  712.                     for offset := projwidth to projsize - 1 - projwidth do begin
  713.                             curval := BAND(p^, 255);
  714.                             prevval := BAND(ptr(ord4(p) - 1)^, 255);
  715.                             nextval := BAND(ptr(ord4(p) + 1)^, 255);
  716.                             aboveval := BAND(ptr(ord4(p) - projwidth)^, 255);
  717.                             belowval := BAND(ptr(ord4(p) + projwidth)^, 255);
  718.                             if (curval = 255) and (prevval <> 255) and (nextval <> 255) and (aboveval <> 255) and (belowval <> 255) then
  719.                                 p^ := (prevval + nextval + aboveval + belowval) div 4;
  720.                             p := ptr(ord4(p) + 1);
  721.                         end;
  722.                 end;
  723.             if (SaveProjections) or (n = 1) then
  724.                 BlockMove(projptr, Info^.PicBaseAddr, projsize)         {whole ROI write to projection image}
  725.             else
  726.                 BlockMove(projptr, Info^.StackInfo^.PicBaseH[n]^, projsize);
  727.             UpdateMeter(-1, '');        {dispose of meter}
  728.             if cancelled then begin
  729.                     if n > 1 then
  730.                         DeleteSlice;
  731.                     leave;
  732.                 end;
  733.             if (SaveProjections) then begin
  734.                     SaveAs('', 0);                                    {just save and put away current image after creating it}
  735.                     ignore := CloseAWindow(info^.wptr);
  736.                 end
  737.             else if n = 1 then begin  {create new stack for first projection if not saving projections}
  738.                     if not MakeStackFromWindow then
  739.                         begin Abort; exit(DoProjection) end
  740.                 end;
  741.             theta := (theta + AngleInc) mod 360;
  742.             UpdatePicWindow;
  743.         end;     {for}
  744.     SaveAllState := NoSaveAll;
  745.     if SaveProjectionsTemp then                 {turn this back off if we turned it on due to lack of memory}
  746.         SaveProjections := FALSE;
  747.     DisposeProjectionPtrs(projptr, opaptr, brightcueptr, zbufptr, countbufptr, cuezbufptr, sumbufptr);
  748.     SetPort(tPort);
  749.     DestInfo := info;
  750.     info := SourceInfo;
  751.     SelectSlice(info^.StackInfo^.CurrentSlice);
  752.     if AutoSelectAll then
  753.         KillRoi;
  754.     info := DestInfo;
  755. end;     {procedure DoProjection}
  756.  
  757.  
  758.  
  759. {******************************************************************************}
  760. {*     This procedure allows the user to set parameters for projection in a large dialog box.                                  *}
  761. {******************************************************************************}
  762. function ShowProjectDialogBox: boolean;
  763.     const
  764.         ProjectOptionsID = 128;
  765.         SliceIntervalID = 3;
  766.         InitAngleID = 4;
  767.         TotalAngleID = 5;
  768.         AngleIncID = 6;
  769.         TransparencyLowerID = 7;
  770.         TransparencyUpperID = 8;
  771.         OpacityID = 9;
  772.         DepthCueSurfID = 10;
  773.         DepthCueIntID = 11;
  774.         RotationAboutXID = 12;
  775.         RotationAboutYID = 13;
  776.         RotationAboutZID = 14;
  777.         SaveProjectionsID = 15;
  778.         MinProjSizeID = 16;
  779.         NearestID = 28;
  780.         BrightestID = 29;
  781.         MeanID = 30;
  782.     var
  783.         mylog: Dialogptr;                                           {pointer to dialog box}
  784.         i, item, alldone: integer;
  785.         SaveInitAngle, SaveTotalAngle, SaveAngleInc: integer;
  786.         SaveOpacity: integer;
  787.         SaveAxisOfRotation: AxisType;
  788.         SaveSaveProjections, SaveCloseSlices, SaveMinProjSize: Boolean;
  789.         SaveLower, SaveUpper: integer;
  790.         PercentSurf, PercentInt: integer;
  791.         interval: extended;
  792. begin
  793.     InitCursor;
  794.     Interval := info^.StackInfo^.SliceSpacing;
  795.     if Interval <= 0.0 then
  796.         Interval := 1.0;
  797.     SaveInitAngle := InitAngle;
  798.     SaveTotalAngle := TotalAngle;
  799.     SaveAngleInc := AngleInc;
  800.     SaveOpacity := Opacity;
  801.     SaveAxisOfRotation := AxisOfRotation;
  802.     SaveSaveProjections := SaveProjections;
  803.     SaveMinProjSize := MinProjSize;
  804.     SaveLower := TransparencyLower;
  805.     SaveUpper := TransparencyUpper;
  806.     PercentSurf := 100 - DepthCueSurf;
  807.     PercentInt := 100 - DepthCueInt;
  808.     if DensitySlicing then
  809.         with info^ do begin
  810.                 TransparencyLower := SliceStart;
  811.                 TransparencyUpper := SliceEnd;
  812.             end;
  813.     mylog := GetNewDialog(ProjectOptionsID, nil, pointer(-1));
  814.     SetDReal(MyLog, SliceIntervalID, Interval, 1);
  815.     SelectdialogItemText(MyLog, SliceIntervalID, 0, 32767);
  816.     SetDNum(MyLog, InitAngleID, InitAngle);
  817.     SetDNum(MyLog, TotalAngleID, TotalAngle);
  818.     SetDNum(MyLog, AngleIncID, AngleInc);
  819.     SetDNum(MyLog, TransparencyLowerID, TransparencyLower);
  820.     SetDNum(MyLog, TransparencyUpperID, TransparencyUpper);
  821.     SetDNum(MyLog, OpacityID, Opacity);
  822.     SetDNum(MyLog, DepthCueSurfID, PercentSurf);
  823.     SetDNum(MyLog, DepthCueIntID, PercentInt);
  824.     OutlineButton(MyLog, ok, 16);
  825.     SetDlogItem(MyLog, RotationAboutXID, ord(AxisOfRotation = XAxis));
  826.     SetDlogItem(MyLog, RotationAboutYID, ord(AxisOfRotation = YAxis));
  827.     SetDlogItem(MyLog, RotationAboutZID, ord(AxisOfRotation = ZAxis));
  828.     SetDlogItem(MyLog, NearestID, ord(ProjectionMethod = NearestPoint));
  829.     SetDlogItem(MyLog, BrightestID, ord(ProjectionMethod = BrightestPoint));
  830.     SetDlogItem(MyLog, MeanID, ord(ProjectionMethod = MeanValue));
  831.     SetDlogItem(MyLog, SaveProjectionsID, ord(SaveProjections));
  832.     SetDlogItem(MyLog, MinProjSizeID, ord(MinProjSize));
  833.     alldone := 0;
  834.     repeat  {if we don't do it this way, ModalDialog throws us into code checking after each keystroke}
  835.         repeat   {meaning you can't type in a 2 digit number}
  836.             ModalDialog(nil, item);
  837.             if item = SaveProjectionsID then begin
  838.                     SaveProjections := not SaveProjections;
  839.                     SetDlogItem(MyLog, SaveProjectionsID, ord(SaveProjections));
  840.                 end;
  841.             if item = MinProjSizeID then begin
  842.                     MinProjSize := not MinProjSize;
  843.                     SetDlogItem(MyLog, MinProjSizeID, ord(MinProjSize));
  844.                 end;
  845.             if (item = RotationAboutXID) or (item = RotationAboutYID) or (item = RotationAboutZID) then begin
  846.                     case item of
  847.                         RotationAboutXID: 
  848.                             AxisOfRotation := XAxis;
  849.                         RotationAboutYID: 
  850.                             AxisOfRotation := YAxis;
  851.                         RotationAboutZID: 
  852.                             AxisOfRotation := ZAxis;
  853.                     end;     {case}
  854.                     SetDlogItem(MyLog, RotationAboutXID, ord(AxisOfRotation = XAxis));
  855.                     SetDlogItem(MyLog, RotationAboutYID, ord(AxisOfRotation = YAxis));
  856.                     SetDlogItem(MyLog, RotationAboutZID, ord(AxisOfRotation = ZAxis));
  857.                 end;
  858.             if (item >= nearestID) and (item <= MeanID) then begin
  859.                     case item of
  860.                         NearestID: 
  861.                             ProjectionMethod := NearestPoint;
  862.                         BrightestID: 
  863.                             ProjectionMethod := BrightestPoint;
  864.                         MeanID: 
  865.                             ProjectionMethod := MeanValue;
  866.                     end;
  867.                     SetDlogItem(MyLog, NearestID, ord(projectionMethod = NearestPoint));
  868.                     SetDlogItem(MyLog, BrightestID, ord(projectionMethod = BrightestPoint));
  869.                     SetDlogItem(MyLog, MeanID, ord(projectionMethod = MeanValue));
  870.                 end;
  871.         until (item = ok) or (item = cancel);
  872.         alldone := 1;
  873.         if (item = ok) then begin  {check all the values that could have been entered, don't know which were changed}
  874.                 Interval := GetDReal(MyLog, SliceIntervalID);
  875.                 if (Interval <= 0.0) or (Interval > 1023.0) then begin
  876.                         Interval := info^.StackInfo^.SliceSpacing;
  877.                         SetDReal(MyLog, SliceIntervalID, Interval, 1);
  878.                         beep;
  879.                         alldone := 0;
  880.                     end;  {if Interval}
  881.                 InitAngle := GetDNum(MyLog, InitAngleID);
  882.                 if (InitAngle < 0) or (InitAngle > 360) then begin
  883.                         InitAngle := SaveInitAngle;
  884.                         SetDNum(MyLog, InitAngleID, InitAngle);
  885.                         beep;
  886.                         alldone := 0;
  887.                     end;  {if InitAngle}
  888.                 TotalAngle := GetDNum(MyLog, TotalAngleID);
  889.                 if (TotalAngle < 0) or (TotalAngle > 360) then begin
  890.                         TotalAngle := SaveTotalAngle;
  891.                         SetDNum(MyLog, TotalAngleID, TotalAngle);
  892.                         beep;
  893.                         alldone := 0;
  894.                     end;  {if TotalAngle}
  895.                 AngleInc := GetDNum(MyLog, AngleIncID);
  896.                 if (AngleInc < 0) or (AngleInc > 360) then begin
  897.                         AngleInc := SaveAngleInc;
  898.                         SetDNum(MyLog, AngleIncID, AngleInc);
  899.                         beep;
  900.                         alldone := 0;
  901.                     end;  {if AngleInc}
  902.                 TransparencyLower := GetDNum(MyLog, TransparencyLowerID);
  903.                 if (TransparencyLower < 0) or (TransparencyLower > 255) then begin
  904.                         TransparencyLower := SaveLower;
  905.                         SetDNum(MyLog, TransparencyLowerID, TransparencyLower);
  906.                         beep;
  907.                         alldone := 0;
  908.                     end;  {if TransparencyLower}
  909.                 TransparencyUpper := GetDNum(MyLog, TransparencyUpperID);
  910.                 if (TransparencyUpper < 0) or (TransparencyUpper > 255) then begin
  911.                         TransparencyUpper := SaveUpper;
  912.                         SetDNum(MyLog, TransparencyUpperID, TransparencyUpper);
  913.                         beep;
  914.                         alldone := 0;
  915.                     end;  {if TransparencyUpper}
  916.                 Opacity := GetDNum(MyLog, OpacityID);
  917.                 if (Opacity < 0) or (Opacity > 100) then begin
  918.                         Opacity := SaveOpacity;
  919.                         SetDNum(MyLog, OpacityID, Opacity);
  920.                         beep;
  921.                         alldone := 0;
  922.                     end;  {if Opacity}
  923.                 PercentSurf := GetDNum(MyLog, DepthCueSurfID);
  924.                 if (PercentSurf < 0) or (PercentSurf > 100) then begin
  925.                         PercentSurf := 100 - DepthCueSurf;
  926.                         SetDNum(MyLog, DepthCueSurfID, PercentSurf);
  927.                         beep;
  928.                         alldone := 0;
  929.                     end;  {if DepthCueSurf}
  930.                 PercentInt := GetDNum(MyLog, DepthCueIntID);
  931.                 if (PercentInt < 0) or (PercentInt > 100) then begin
  932.                         PercentInt := 100 - DepthCueInt;
  933.                         SetDNum(MyLog, DepthCueIntID, PercentInt);
  934.                         beep;
  935.                         alldone := 0;
  936.                     end;  {if DepthCueInt}
  937.                 info^.StackInfo^.SliceSpacing := Interval;
  938.             end;
  939.     until (alldone = 1);
  940.     DisposeDialog(mylog);
  941.     if item = cancel then begin                       {if Cancel, keep the saved values}
  942.             InitAngle := SaveInitAngle;
  943.             TotalAngle := SaveTotalAngle;
  944.             AngleInc := SaveAngleInc;
  945.             Opacity := SaveOpacity;
  946.             AxisOfRotation := SaveAxisOfRotation;
  947.             SaveProjections := SaveSaveProjections;
  948.             MinProjSize := SaveMinProjSize;
  949.             TransparencyLower := SaveLower;
  950.             TransparencyUpper := SaveUpper;
  951.             ShowProjectDialogBox := false;
  952.         end
  953.     else begin
  954.             DepthCueSurf := 100 - PercentSurf;
  955.             DepthCueInt := 100 - PercentInt;
  956.             ShowProjectDialogBox := true;
  957.         end;
  958. end;
  959.  
  960.  
  961. procedure Project;
  962. begin
  963.     if ShowProjectDialogBox then
  964.         DoProjection;
  965. end;
  966.  
  967.  
  968. end.